﻿/*
 * Сделано в SharpDevelop.
 * Пользователь: Badanin M.V.
 * Дата: 24.06.2013
 * Время: 16:33
 * Проект: РПН Регион 2013
 * Распространяется под лицензией GPL v3
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Linq;
using Region.Utils;

namespace Region.Forms
{
  /// <summary>
  /// Description of Form2.
  /// </summary>
  public partial class AutoJournal : Form
  {
    Engine m_engine;
    //Параметры вывода журнала
    readonly TimeSpan _Interval = new TimeSpan(0,30,0);
    const int p_NumDays = 10;
    Int32 p_StartMinutes = 9*60;//Начало дня(в минутах)
    Int32 p_PauseStartMinutes = 13*60;//Начало дня(в минутах)
    Int32 p_PauseEndMinutes = 14*60;//Начало дня(в минутах)
    Int32 p_EndMinutes = 18*60; //Окончание дня(в минутах)
    Int32 p_EndMinutes2 = 17*60;//Окончание предпразднечного дня(в минутах)
    Color p_WorkColor = Color.DarkOrange;
    Color p_FreeColor = Color.LightGreen;
    const Int32 driverColumnWidth = 150; // Ширена столбца
    const Int32 dayColumnWidth =100; // Ширена столбца
    //Выходные дни
    Dictionary<DateTime,Boolean> Days;
    bool DayOff=false;//Текущий день выходной
    bool DayOffNext=false;//Следущий день выходной(сокращённый день)
    SQLResult Drivers = null;// Список водителей
    TSelect current = new TSelect();
    
    struct TSelect
    {
    	public DateTime CurrentDay;
    	public Int32 DriverID;// выбранный водитель
    	public Boolean Driver;//Выбран водитель
    	public DateTime TimeStartValue;
    	public Boolean TimeStart;
    	public DateTime TimeEndValue;
    	public Boolean TimeEnd;
    	    	
    }
    class PoleItem
    {
      public Int32 DriverID;
      public DateTime Time;
      public Int32 Period;
      public Boolean Lock;
      public AutoList.Line Line;
    }
    
    List<PoleItem> processPole(DateTime Day)
    {
      DayOff = Days.ContainsKey(current.CurrentDay);
      DayOffNext = Days.ContainsKey(current.CurrentDay.AddDays(1));

      List<PoleItem> Poles = new List<AutoJournal.PoleItem>();
      Dictionary<Int32,Dictionary<DateTime,PoleItem>> PolesD = new Dictionary<Int32,Dictionary<DateTime,PoleItem>>();
      DateTime DayStart=Day.AddMinutes(0);
      DateTime DayEnd=Day.AddMinutes(24*60);
      foreach(var d in Drivers)
        for(DateTime Time = DayStart;Time<DayEnd;Time+=_Interval)
      {
        Int32 DriverID = (Int32)(d.Value["DriverID"]);
        PoleItem pi = new PoleItem();
        pi.DriverID = DriverID;
        pi.Time = Time;
        pi.Lock = !isFree(Time);
        pi.Line = null;
        Poles.Add(pi);
        if (!PolesD.ContainsKey(DriverID)) PolesD[DriverID] =  new Dictionary<DateTime,PoleItem>();
        PolesD[DriverID][Time] = pi;
      }
      // Получить список заявок и указать что время занято
      var list = new AutoList(m_engine);
      list.setWhere("Day",current.CurrentDay);
      list.Filter();
      for(Int32 i=0;i<list.NumLines;i++)
      {
        AutoList.Line line = list.getLine(i);
        Int32 DriverID = line.DriverID;
        DateTime Start=Day.AddMinutes(line.TimeStart);
        DateTime End=Day.AddMinutes(line.TimeEnd);
        for(DateTime Time = Start;Time<End;Time+=_Interval)
        {
          PoleItem p = PolesD[DriverID][Time];
          p.Line = line;
          p.Lock = true;
        }
      }
      foreach(var d in Drivers)
      {
        Int32 DriverID = (Int32)(d.Value["DriverID"]);
        for(DateTime Time = DayStart;Time<DayEnd;Time+=_Interval)
        {
          PoleItem pi = PolesD[DriverID][Time];
          if (pi.Lock==false)
            for(DateTime Time2 = Time;Time2<DayEnd;Time2+=_Interval)
              if (PolesD[DriverID][Time2].Lock==false)
                pi.Period+=(Int32)_Interval.TotalMinutes;
              else
                break;                
          
        }
      }
      return Poles;
    }
    String endTimeStr(DateTime Time)
    {
      TimeSpan p = (Time-current.TimeStartValue).Add(_Interval);
      String text = "";
      Int32 h = ((Int32)p.Hours);
      Int32 m = ((Int32)p.Minutes);
      if (h>0) text += h.ToString()+" ч.";
      if (m>0) text += m.ToString()+" мин.";
      text+=" до "+Time.Add(_Interval).ToShortTimeString();
      return text;
    }
    
    void ShowSelect()
    {
    	
      IEnumerable<PoleItem> allPoles = processPole(current.CurrentDay);
      Dictionary<UInt32,Boolean> LDrivers = new Dictionary<UInt32,Boolean>();
      IEnumerable<PoleItem> freePoles = from p in allPoles where p.Lock==false select p;
      
      //Список времени начала
      IEnumerable<PoleItem> startPoles = freePoles;
      if (current.Driver) startPoles = from d in startPoles where d.DriverID==current.DriverID select d;
      IEnumerable<DateTime> starts = (from a in startPoles group a by a.Time into a orderby a.Key select a.Key );
      startList.SelectedIndexChanged -= StartListSelectedIndexChanged;
      startList.Items.Clear();   
      startList.Items.Add(new ListItemValue("[Не выбран]",null));
      foreach(DateTime d in starts) 
        startList.Items.Add(new ListItemValue(d.ToShortTimeString(),d));
      if (current.TimeStart) 
        startList.SelectedItem = new ListItemValue(current.TimeStartValue.ToShortTimeString(),current.TimeStartValue);
      startList.SelectedIndexChanged += StartListSelectedIndexChanged;
      //Список времени окончания
      if (current.TimeStart)
      {
        endList.SelectedIndexChanged -= EndListSelectedIndexChanged;
        IEnumerable<PoleItem> endPoles = freePoles;
        if (current.Driver) endPoles = from d in endPoles where d.DriverID==current.DriverID select d;
        Int32 period = (from a in endPoles where a.Lock==false && a.Time==current.TimeStartValue select a).Max(p=>p.Period);   
        endList.Items.Clear();
        endList.Items.Add(new ListItemValue("[Не выбран]",null));
        DateTime endTime = current.TimeStartValue.AddMinutes(period);
        for(DateTime Time = current.TimeStartValue;Time<endTime;Time+=_Interval)
          endList.Items.Add(new ListItemValue(endTimeStr(Time),Time));
        endList.Enabled = true;
        if (current.TimeEnd)
          endList.SelectedItem = new ListItemValue(endTimeStr(current.TimeEndValue),current.TimeEndValue);
        endList.SelectedIndexChanged += EndListSelectedIndexChanged;
      }
      else
      {
      	current.TimeEnd = false;
  		endList.Enabled = false;
        endList.Items.Clear();
      }
      //Список водителей
      IEnumerable<PoleItem> driversPoles = freePoles;
      if (current.TimeStart) driversPoles = from d in driversPoles where d.Time==current.TimeStartValue select d; 
      if (current.TimeStart&&current.TimeEnd)
      {
      	Int32 p = (Int32)(current.TimeEndValue-current.TimeStartValue).Add(_Interval).TotalMinutes;
      	driversPoles = from d in driversPoles where d.Period>=p select d; 
      }
      IEnumerable<Int32> drivers = (from a in driversPoles group a by a.DriverID into a select a.Key);
      DriverList.SelectedIndexChanged -= DriverListSelectedIndexChanged;
      DriverList.Items.Clear();
      DriverList.Items.Add(new ListItemValue("[Не выбран]",0));
      foreach(Int32 d in drivers) DriverList.Items.Add(new ListItemValue(m_engine.getDriver(d).FIO,d));
      if (current.Driver) 
        DriverList.SelectedItem = new ListItemValue(m_engine.getDriver(current.DriverID).FIO,current.DriverID);
      DriverList.SelectedIndexChanged += DriverListSelectedIndexChanged;
      // Список специалистов
      userList.Items.Clear();
      userList.Items.Add(new ListItemValue(m_engine.CurrentUser.FIO,m_engine.CurrentUser.UserID));
      userList.SelectedItem = new ListItemValue(m_engine.CurrentUser.FIO,m_engine.CurrentUser.UserID); 
      //
     createButton.Enabled = current.Driver && current.TimeStart && current.TimeEnd;
      //     DriverList.Items.Add(new ListItemValue(m_engine.getDriver(d).FIO,d));
    }
    void ShowTimeLine(DateTime StartTime,DateTime EndTime,TimeSpan Interval)
    {
    }
    Button AddPole(TableLayoutPanel Panel, Int32 Col,Int32 Row,Int32 ColSpan,Int32 RowSpan,String Caption, Color color,Boolean Enable=true)
    {
      var b = new Button();
      b.TextAlign = ContentAlignment.MiddleCenter;
      b.Text =  Caption;//""+Time.ToString("HH:mm") + D.Value[Time];
      b.FlatStyle = FlatStyle.Flat;
      b.BackColor = color;
      b.Dock = DockStyle.Fill;
      b.Enabled = Enable;
      b.Margin = new Padding(0);

      Panel.Controls.Add(b, Col, Row);
      Panel.SetRowSpan(b, RowSpan);
      Panel.SetColumnSpan(b, ColSpan);
      return b;
    }
    bool isFree(DateTime Time)
    {
      if (DayOff) return false;
      Int32 t = Time.Minute+Time.Hour*60;
      if (t>=p_StartMinutes && t<p_PauseStartMinutes) return true;
      if (DayOffNext==false && t>=p_PauseEndMinutes && t<p_EndMinutes) return true;
      if (DayOffNext==true && t>=p_PauseEndMinutes && t<p_EndMinutes2) return true;
      return false;
    }
	void ShowPole(DateTime Day)
    {
      tabControl1.SelectTab(0);
      //tabControl1.Hide();
      current = new TSelect();
      current.CurrentDay = Day;
      
      IEnumerable<PoleItem> allPoles = processPole(current.CurrentDay);
      IEnumerable<DateTime> times = (from a in allPoles where a.Line!=null || a.Lock==false  group a by a.Time into a orderby a.Key select a.Key );
      DateTime DayStart=(times.Count()==0)?Day.AddMinutes(p_StartMinutes):times.Min();
      DateTime DayEnd=(times.Count()==0)?Day.AddMinutes(p_EndMinutes):times.Max().Add(_Interval);
      Int32 N=0;
      Int32 DN=0;
      Visible = false;
      Int32 NumLine = (Int32)((DayEnd-DayStart).TotalMinutes/_Interval.TotalMinutes);
      this.poleLayoutPanel.Controls.Clear();
      this.poleLayoutPanel.ColumnStyles.Clear();
      this.poleLayoutPanel.RowStyles.Clear();
      this.poleLayoutPanel.RowCount = NumLine+1;
      this.poleLayoutPanel.ColumnCount = Drivers.Count+1;
      this.poleLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F) );
      panel1.Width = driverColumnWidth*Drivers.Count+50;
      panel1.Height = 25*NumLine+70;
      daysLayoutPanel.Width=dayColumnWidth*p_NumDays;
      this.Width = ((dayColumnWidth*p_NumDays>driverColumnWidth*Drivers.Count+50)?dayColumnWidth*p_NumDays:driverColumnWidth*Drivers.Count+50)+20;
      this.Height = panel1.Height;
      
      this.daysLayoutPanel.ColumnCount =p_NumDays+1;
      this.daysLayoutPanel.Controls.Clear();
      this.daysLayoutPanel.ColumnStyles.Clear();
      DateTime NowDay = DateTime.Today;
      for(Int32 DayN = 0;DayN<p_NumDays;DayN+=1)
      {
        DateTime NDay = NowDay.AddDays(DayN);
        Button b = AddPole(this.daysLayoutPanel,0+DayN,0,1,1,NDay.ToShortDateString()+" "+NDay.ToString("dddd"),(NDay==Day)?Color.Red:Days.ContainsKey(NDay)?Color.Gray:BackColor);
        b.Tag = NDay;
        b.Click += (o,e)=>
        {
          ShowPole((DateTime)b.Tag);
        };
        this.daysLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, dayColumnWidth) );
      }
      
      // Вывести шапку таблици
      //this.poleLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F) );
      this.poleLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 80F) );
      for(Int32 DriverN = 0;DriverN<Drivers.Count;DriverN+=1)
      {
        String Text = (String)Drivers[DriverN]["FIO"]+"\r\n"+(String)Drivers[DriverN]["Car"]+"\r\n"+(String)Drivers[DriverN]["Tel"];
        
        AddPole(this.poleLayoutPanel,1+DriverN,0,1,1,Text,BackColor);
        this.poleLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, driverColumnWidth) );
      }
      // Вывести первый столбец
      N=1;
      for(DateTime Time = DayStart;Time<DayEnd;Time+=_Interval)
      {
      	TSelect S = new TSelect(){CurrentDay = current.CurrentDay, TimeStart = true, TimeStartValue = Time, Driver = false, DriverID = 0};
        Button b = AddPole(this.poleLayoutPanel,0,N,1,1,Time.ToString("HH:mm"),BackColor,true);
        N++;
      }
      
      // Вывести таблицу
      foreach(var D in Drivers)
      {
        Int32 DriverID = (Int32)D.Value["DriverID"];
        IEnumerable<PoleItem> driverPoles = from t in allPoles where  t.DriverID==DriverID && t.Line!=null orderby t.Time select t;
        Dictionary<DateTime, AutoList.Line> DList =driverPoles.ToDictionary(t=>t.Time,p=>p.Line);
        Int32 LineN=1;
        for(DateTime Time = DayStart;Time<DayEnd;)
        {
          if (DList.ContainsKey(Time))
          {
            
            Int32 n = (Int32)(((TimeSpan)(Day.AddMinutes(DList[Time].TimeEnd)-Time)).TotalMinutes/_Interval.TotalMinutes);
            String TimeStr = Time.ToString("HH:mm")+"-"+Time.AddMinutes(DList[Time].TimeEnd-DList[Time].TimeStart).ToString("HH:mm");
            String UserStr = m_engine.getUser(DList[Time].UserID).FIO;
            String AddressStr = DList[Time].Address;
            String S = TimeStr + "\r\n" + AddressStr + "\r\n"  + UserStr;
            Button b = AddPole(this.poleLayoutPanel,1+DN,LineN,1,n, TimeStr + "\r\n" + AddressStr + "\r\n"  + UserStr, p_WorkColor);
            if (DList[Time].UserID==m_engine.CurrentUser.UserID)
            {
            	b.BackColor = Color.YellowGreen;
            	b.Tag = DList[Time].AutoID;
            	b.Click+= (p,e)=>
            	{
            		if (DialogResult.OK == MessageBox.Show(this,"Удалить заявку:"+S,"Удалить заявку",MessageBoxButtons.OKCancel,MessageBoxIcon.Warning))
            		{
            			m_engine.delAuto((Int32)((Button)p).Tag);
            			ShowPole(current.CurrentDay);
            		}
            	};
            }
            b.Width = 100;
            
            LineN+=n;
            Time=Time.AddMinutes(_Interval.TotalMinutes*n);
          }
          else if (isFree(Time))
          {
          	
          	Button b = AddPole(this.poleLayoutPanel,1+DN,LineN,1,1,Time.ToString("HH:mm")+" Свободно",p_FreeColor,true);
          	b.Tag = new TSelect(){CurrentDay = current.CurrentDay, TimeStart = true, TimeStartValue = Time, Driver = true, DriverID = DriverID};       	
          	b.Click += (s,e)=>
          	        {
          		
        	        	current = (TSelect)(((Button)s).Tag);
          	        	ShowSelect();
          	        	tabControl1.SelectTab(1);
          	      
          	        };
          	
            LineN+=1;
            Time+=_Interval;
          }
          else
          {
            AddPole(this.poleLayoutPanel,1+DN,LineN,1,1,"Не рабоее время",BackColor,false);
            LineN+=1;
            Time+=_Interval;
          }
        }
        DN+=1;
      }
      ShowSelect();
      //tabControl1.Show();
      Visible = true;
      this.panel1.AutoSize = true;
    }    
   
    public AutoJournal(Engine engine)
    {
      m_engine = engine;
      Days = Days = m_engine.getDays();
      Drivers = m_engine.SQLSelect("SELECT * FROM driver");
      //
      // The InitializeComponent() call is required for Windows Forms designer support.
      //
      InitializeComponent();
      
    }
    void DriverListSelectedIndexChanged(object sender, EventArgs e)
    {
      ListItemValue item = DriverList.SelectedItem as ListItemValue;
      current.Driver = false;
      if (item!=null)
      {
        Int32 Value = (Int32)item.Value;
        current.DriverID = Value;
        current.Driver = (Value!=0);
      }
      ShowSelect();
    }
    
    void StartListSelectedIndexChanged(object sender, EventArgs e)
    {
      ListItemValue item = startList.SelectedItem as ListItemValue;
      current.TimeStart = false;
      if (item!=null)
      {
        if (item.Value!=null)
        {
          DateTime Value = (DateTime)item.Value;
          current.TimeStartValue = Value;
          current.TimeStart = true;
        }
      }  
      ShowSelect();      
    }
    
    void EndListSelectedIndexChanged(object sender, EventArgs e)
    {
      ListItemValue item = endList.SelectedItem as ListItemValue;
      current.TimeEnd = false;
      if (item!=null)
      {
        if (item.Value!=null)
        {
          DateTime Value = (DateTime)item.Value;
          current.TimeEndValue = Value;
          current.TimeEnd = true;
        }
      }  
      ShowSelect();       
    }
    
    void CreateButtonClick(object sender, EventArgs e)
    {
    	ListItemValue item = userList.SelectedItem as ListItemValue;
    	Int32 UserID = (Int32)item.Value;
    	String Address = addressTextBox.Text;
    	m_engine.newAuto(current.CurrentDay,(Int32)(current.TimeStartValue-current.CurrentDay).TotalMinutes,(Int32)(current.TimeEndValue-current.CurrentDay+_Interval).TotalMinutes,current.DriverID,UserID,Address);
    	ShowPole(current.CurrentDay);
    }
    
    void AutoJournalLoad(object sender, EventArgs e)
    {
    	ShowPole(DateTime.Today.AddDays(1));
    }
  }
}
